#include <SDL/SDL.h>
#include <iostream>

#include "include/Partie.h"
#include "include/Jeu.h"
#include "include/De.h"
#include "include/Playlist.h"
#include "include/Joueur.h"
#include "include/Monde.h"
#include "include/Territoire.h"
#include "include/MissionStrategy.h"

using namespace std;

void Step::toggle()
{
   switch(step_enum)
   {
      case CHOOSE_ARMY:
         step_enum=CHOOSE_ENEMY;
         break;
      case CHOOSE_ENEMY:
         step_enum=LANCERDE;
         break;
      case LANCERDE:
         step_enum=ATTACK;
         break;
      case ATTACK:
         step_enum=ENDSTEP;
         break;
      case ENDSTEP:
      default:
         step_enum=CHOOSE_ARMY;
         break;
   }
}

Partie::Partie()
   : step(new Step()), 
     territoireArmy(NULL), territoireEnemy(NULL), 
     territoireWinner(NULL), territoireLooser(NULL)
{
   finAnimDe = true;
}

Partie::~Partie()
{
   //printf("Destruction de la Partie!\n");
   vector<Joueur*>::const_iterator joueur_ite;
   for(joueur_ite = joueurs.begin();
       joueur_ite != joueurs.end();
       joueur_ite++)
      delete *joueur_ite;
}

void Partie::resetAllDeState()
{
   for(int i=0; i< Partie::NBDE; i++)
   {
      getDeAttak()[i].toggleRotation();
      getDeDef()[i].toggleRotation();
   }
}

bool Partie::allDeStopped()
{
   for(int i=0; i< Partie::NBDE; i++)
   {
      if( (getDeAttak()[i]).isRotate() 
          || (getDeDef()[i]).isRotate() )
         return false;
   }  
   return true;
}

int Partie::getBestScoreAttak()
{
   int best = 0;
   
   for(int i=0; i< Partie::NBDE; i++)
   {
      if ( best < (getDeAttak()[i]).getNumber() )
         best = (getDeAttak()[i]).getNumber();
   }
   return best;
}

int Partie::getBestScoreDef()
{
   int best = 0;
   
   for(int i=0; i< Partie::NBDE; i++)
   {
      if ( best < (getDeDef()[i]).getNumber() )
         best = (getDeDef()[i]).getNumber();
   }
   return best;
}

void Partie::initFirstPlayer()
{
   currentPlayer = joueurs.begin();
   Jeu::jeu->guinterface.messageInfo = (const char *) *step;
   Jeu::jeu->guinterface.messageInfo += " Appuyez sur la touche ENTRER pour valider votre choix.";
}

void Partie::doStep(Territoire* _territoire)
{
   SDL_Thread* thread_anim = NULL;
   SDL_Thread* thread_de = NULL;
   switch( *step )
   {
      case Step::CHOOSE_ARMY:
         if ( _territoire->appartientAuJoueur(getCurrentPlayer()) )
         {
            Jeu::jeu->playlist->playClic( Playlist::CLIC_OK );
            if ( selectTerritoireArmy(_territoire) )
            {
               thread_anim = SDL_CreateThread(Scene::animCameraCenterTo, (void*) _territoire->getModel3D()->getCenter());
               if ( thread_anim == NULL ) 
               {
                  printf("Unable to create thread: %s\n", SDL_GetError());
                  exit(1);
               }          
            }
         }
         else
            Jeu::jeu->playlist->playClic( Playlist::CLIC_NOK );
         break;
      case Step::CHOOSE_ENEMY:
         if ( !_territoire->appartientAuJoueur(getCurrentPlayer())
              && _territoire->isBorderOf(territoireArmy) )
         {
            Jeu::jeu->playlist->playClic( Playlist::CLIC_OK );
            selectTerritoireEnemy(_territoire);
         }
         else
            Jeu::jeu->playlist->playClic( Playlist::CLIC_NOK );
         break;
      case Step::LANCERDE:
         if ( !Jeu::jeu->getScene()->getAnimationState( Animation::DE ) )
          {
             thread_de = SDL_CreateThread(Scene::animDe, this);
             if ( thread_de == NULL ) 
             {
                printf("Unable to create thread: %s\n", SDL_GetError());
                exit(1);
             }
          }
         break;
      case Step::ATTACK:
         attack();
         break;
      case Step::ENDSTEP:
         if ( territoireArmy && territoireEnemy )
         {
            territoireArmy->toggleSelected();
            territoireArmy->toggleHauteur();
            territoireArmy = NULL;
            territoireEnemy->toggleSelected();
            territoireEnemy->toggleHauteur();
            territoireEnemy = NULL;
         }
         break;
   }
}

void Partie::nextStep()
{
   switch(*step)
   {
      case Step::CHOOSE_ARMY:        
         if ( territoireArmy && territoireArmy->hasEnemyInBorders() )
            if ( territoireArmy->countNbPions() == 1 )
            {
               Jeu::jeu->guinterface.messageInfo = "Votre armee n'est pas assez grande pour attaquer !";
               return;
            }
            else
               step->toggle();
         break;
      case Step::CHOOSE_ENEMY:
         if ( territoireEnemy )
         {
            step->toggle();
            territoireArmy->toggleBordersHauteur();
            territoireEnemy->toggleHauteur();
            doStep();
            //nextStep();
            //return;
         }
         break;
      case Step::LANCERDE:
         if ( isEndOfAnimDe() )
         {
            Jeu::jeu->getScene()->stopAnimation( Animation::DE );
            step->toggle();
            doStep();
            nextStep();
            return;
         }
         break;
      case Step::ATTACK:
         if( territoireWinner && territoireLooser )
         { 
            step->toggle();

            if ( territoireWinner->getJoueur() == getCurrentPlayer() )
            {
               Jeu::jeu->playlist->playVictory();
               Jeu::jeu->guinterface.messageInfo = string( "Vous remportez la bataille contre " )
                  + string( territoireWinner->getJoueur()->getNom() )
                  + string( ", vous pouvez rejouer !" );
            }
            else
            {
               Jeu::jeu->playlist->playDefeat();
               Jeu::jeu->guinterface.messageInfo = string( "Vous perdez contre " )
                  + string( territoireWinner->getJoueur()->getNom() )
                  + string( " pour le territoire " )
                  + string( territoireEnemy->getNom() );
            }
            Joueur* joueurLooser = territoireLooser->getJoueur();
            int nbPionsLooser = territoireLooser->countNbPions();
            territoireLooser->removePion( nbPionsLooser );
            territoireLooser->addPion(joueurLooser, nbPionsLooser - 1);
            if ( territoireLooser->countNbPions() == 0 )
            {
               int nbPionsWinner = territoireWinner->countNbPions();
               territoireWinner->removePion( nbPionsWinner - 1 );
               territoireLooser->addPion(territoireWinner->getJoueur(), nbPionsWinner - 1);
               Jeu::jeu->guinterface.messageInfo = string( territoireEnemy->getNom() )
                  + string( " vous appartient maintenant !");
            }
            return;
         }
         break;
      case Step::ENDSTEP:      
         if ( !getCurrentPlayer()->missionAccomplie() )
         {
            doStep();  
            step->toggle();
            if ( !territoireWinner->appartientAuJoueur(getCurrentPlayer()) )
               nextPlayer();
            territoireWinner = NULL;
            territoireLooser = NULL;
         }
         else
         {
            Jeu::jeu->guinterface.messageInfo = string("BRAVO ")
               + string( getCurrentPlayer()->getNom() ) 
               + string(", vous avez accomplie votre mission !");
            return;
         }         
         break;
   }
   Jeu::jeu->guinterface.messageInfo = (const char *) *step;
   Jeu::jeu->guinterface.messageInfo += " Appuyez sur la touche ENTRER pour continuer.";
}

Joueur * Partie::nextPlayer()
{
   currentPlayer++;
   if ( currentPlayer == joueurs.end() )
      currentPlayer = joueurs.begin();
   SDL_Thread* thread_anim = SDL_CreateThread(Scene::animNomJoueur, NULL);
   if ( thread_anim == NULL ) 
   {
      printf("Unable to create thread: %s\n", SDL_GetError());
      exit(1);
   }
   return *currentPlayer;
}

bool Partie::selectTerritoireArmy(Territoire * _territoire)
{
   if ( territoireArmy && territoireArmy == _territoire )
   {
      territoireArmy->toggleSelected();
      territoireArmy->toggleHauteur();
      territoireArmy->toggleBordersHauteur();
      territoireArmy = NULL;
   }
   else
      if ( territoireArmy != _territoire )
      {
         if ( territoireArmy )
         {
            territoireArmy->toggleSelected();
            territoireArmy->toggleHauteur();
            territoireArmy->toggleBordersHauteur();
         }
         territoireArmy = _territoire;
         territoireArmy->toggleSelected();
         territoireArmy->toggleHauteur();
         territoireArmy->toggleBordersHauteur();
         return true;
      }
   return false;
}

bool Partie::selectTerritoireEnemy(Territoire * _territoire)
{
   if ( territoireEnemy && territoireEnemy == _territoire )
   {
      territoireEnemy->toggleSelected();
      territoireEnemy = NULL;
   }
   else
      if ( territoireEnemy != _territoire )
      {
         if ( territoireEnemy )
            territoireEnemy->toggleSelected();
         territoireEnemy = _territoire;
         territoireEnemy->toggleSelected();
         return true;
      }
   return false;
}

void Partie::attack()
{
   /*srand( time(NULL) );
   int result_territoireArmy, result_territoireEnemy;
   result_territoireArmy = rand() % 6;
   result_territoireEnemy = rand() % 6;*/


   // En cas d'egalite c'est le territoireEnemy qui est vainqueur
   if ( getResultArmy() <= getResultEnemy() )
   {
      territoireWinner = territoireEnemy;
      territoireLooser = territoireArmy;
   }
   else
   {
      territoireWinner = territoireArmy;
      territoireLooser = territoireEnemy;
   }

   SDL_Thread* thread_anim = SDL_CreateThread(Scene::animFeu, (void*) territoireLooser->getModel3D()->getCenter());
   if ( thread_anim == NULL ) 
   {
      printf("Unable to create thread: %s\n", SDL_GetError());
      exit(1);
   }
}

bool contains(vector<int> * _vector, int _val)
{
   vector<int>::const_iterator ite;
   for(ite = _vector->begin();
       ite != _vector->end();
       ite++)
   {
      if(*ite == _val)
         return true;
   }
   return false;
}

void Partie::initPlayers()
{
   //jaune,rouge,bleu,noir,violet,vert
   int nbJoueurs = 0, couleur = 0;
   string nom_tmp;
   vector<int> missions;
   vector<int> couleurs;
   srand( time(NULL) );
   int random_mission_id;
   
   do
   {
      cout << "Saisir le nombre de joueurs [2-6]: ";
      cin >> nbJoueurs;
   } 
   while( nbJoueurs < 2 || nbJoueurs > 6 );
   
   for(int i=0; i<nbJoueurs; i++)
   {
      cout << "nom du joueur " << (i+1) << ": ";
      cin >> nom_tmp;
      
      do
      {
         cout << "choisissez une couleur:" << endl;
         cout << "\t0. jaune" << endl;
         cout << "\t1. rouge" << endl;
         cout << "\t2. bleu" << endl;
         cout << "\t3. noir" << endl;
         cout << "\t4. violet" << endl;
         cout << "\t5. vert" << endl;
         cin >> couleur;
      }
      while( contains(&couleurs, couleur) );
      couleurs.push_back(couleur);
      
      getJoueurs()->push_back( new Joueur(nom_tmp.c_str(), (Couleur::CouleurEnum)couleur) );
      
      do { random_mission_id = rand() % 8; } //14;
      while( contains(&missions,random_mission_id) );
      missions.push_back(random_mission_id);

      getJoueurs()->back()->setMission( MissionStrategy::createMission(random_mission_id) );
   }
   initFirstPlayer();
}

/*
  2 joueurs : chacun 40 pions
  3 joueurs : chacun 35 pions
  4 joueurs : chacun 30 pions
  5 joueurs : chacun 25 pions
  6 joueurs ; chacun 20 pions
*/
void Partie::distribuerTerritoires()
{
   int nbTerritoires = Jeu::jeu->getMonde()->countTerritoires();
   int nbTerritoiresParJoueur = nbTerritoires / getJoueurs()->size();
   int nbPions, nbPionParTerritoire;

   switch( (int)getJoueurs()->size() )
   {
      case 2:
         nbPions = 40; break;
      case 3:
         nbPions = 35; break;
      case 4:
         nbPions = 30; break;
      case 5:
         nbPions = 25; break;
      case 6:
         nbPions = 20; break;
      default:
         nbPions = 40;
   }
   nbPionParTerritoire = ( nbPions / nbTerritoiresParJoueur) * 6;
   
   srand( time(NULL) );
   int random;
   Territoire * territoire_tmp;
   for(int i=0; i<(int) getJoueurs()->size(); i++)
   {
      cout << "> repartition des armees du joueur " << (i+1) << endl;
      for(int j=0; j<nbTerritoiresParJoueur; j++)
      {    
         do
         {
            random = rand() % nbTerritoires;
            territoire_tmp = Jeu::jeu->getMonde()->getIndexedTerritoire( random );
         }
         // on force le joueur a occuper le maximum de territoires
         while( territoire_tmp->getJoueur() != NULL );
         //&& territoire_tmp->getJoueur() != joueurs[i] );

         getJoueur(i)->addPion(territoire_tmp, nbPionParTerritoire);
      }
   }
}
